package service

import (
	"bufio"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"
	"usbipproxy/domain/vo"
)

type SwDeviceWindowsServiceImpl struct {
	rwLock    sync.RWMutex
	sessMap   map[int64]*vo.SwDeviceInfo
	clientSvc UsbIpClientCmdService
}

func (s *SwDeviceWindowsServiceImpl) StopUsbBusControl(connId int64) error {
	s.rwLock.Lock()
	defer s.rwLock.Unlock()
	info := s.sessMap[connId]
	if info.GetStatus() != vo.SwDeviceStatusStopped {
		info.SetStatus(vo.SwDeviceStatusStopped)
		info.CloseStopChan()
	}

	return nil
}

func (s *SwDeviceWindowsServiceImpl) StartUsbBusControl(connId int64, sid int32) error {
	s.rwLock.RLock()
	qryInfo := s.sessMap[connId]
	if qryInfo.GetStatus() == vo.SwDeviceStatusRunning {
		s.rwLock.RUnlock()
		log.Infof("StartUsbBusControl connId:%v sid:%v is running", connId, sid)
		return nil
	}
	s.rwLock.RUnlock()

	dInfo := vo.NewSwDeviceInfo()
	s.rwLock.Lock()
	s.sessMap[connId] = dInfo
	dInfo.SetStatus(vo.SwDeviceStatusRunning)
	dInfo.SetSid(sid)
	s.rwLock.Unlock()

	go func() {

		defer func() {
			s.clientSvc.DetachByParent(connId)
		}()

		ex, err := os.Executable()
		if err != nil {
			panic(err)
		}
		exPath := filepath.Dir(ex)

		swdeviceExe := filepath.Join(exPath, "swdevice.exe")
		cmdStrs := []string{swdeviceExe, "-sid", fmt.Sprintf("%d", sid), "-instance_id", fmt.Sprintf("%d", connId)}
		log.Infof("StartUsbBusControl cmdStrs:%+v", cmdStrs)
		cmd := exec.Command(cmdStrs[0], cmdStrs[1:]...)

		// 创建管道获取标准输出
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Errorf("cmd.StdoutPipe err:%v", err)
		}

		stderr, err := cmd.StderrPipe()
		if err != nil {
			log.Errorf("cmd.StderrPipe err:%v", err)
		}

		stdin, err := cmd.StdinPipe()
		if err != nil {
			log.Errorf("can not find stdin pipeline: %v", err)
			return
		}

		// 启动命令
		if err := cmd.Start(); err != nil {
			log.Errorf("cmd.Start err:%v", err)
		}
		log.Infof("Waiting for command:%+v to finish...", cmdStrs)
		var wg sync.WaitGroup
		wg.Add(3)

		// 处理标准输出
		go func() {
			defer wg.Done()

			// 使用带缓冲的大读取器
			reader := bufio.NewReaderSize(stdout, 1024*64) // 64KB buffer
			for {
				// 使用 ReadBytes 而不是 Scanner
				line, err := reader.ReadBytes('\n')
				if err != nil {
					if err != io.EOF {
						log.Errorf("stdout读取错误: %v", err)
					}
					break
				}
				if len(line) > 0 {
					// 去除尾部的换行符
					log.Infof("usbipd stdout info: %s", strings.TrimSpace(string(line)))
				}
			}
		}()

		// 处理标准输出
		go func() {
			defer wg.Done()

			// 使用带缓冲的大读取器
			reader := bufio.NewReaderSize(stderr, 1024*64) // 64KB buffer
			for {
				// 使用 ReadBytes 而不是 Scanner
				line, err := reader.ReadBytes('\n')
				if err != nil {
					if err != io.EOF {
						log.Errorf("stderr 读取错误: %v", err)
					}
					break
				}
				if len(line) > 0 {
					// 去除尾部的换行符
					log.Infof("usbipd stderr info: %s", strings.TrimSpace(string(line)))
				}
			}
		}()

		go func() {
			defer wg.Done()

			for {
				select {
				case <-dInfo.StopChan:
					dataToSend := "exit\r\n"
					_, err = io.WriteString(stdin, dataToSend)
					if err != nil {
						log.Errorf("写入标准输入失败: %v", err)
					}

					// 关闭标准输入，告知进程数据已发送完毕
					if err := stdin.Close(); err != nil {
						log.Errorf("关闭标准输入失败: %v", err)
					}
					log.Infof("recv stop chan to exit")
					return
				}
			}
		}()

		wg.Wait()

		// 等待命令结束
		/*
			if err := cmd.Wait(); err != nil {
				log.Errorf("ProgramServiceWindowsImpl cmd:%+v wait err:%v", cmdStrs, err)
			}
		*/

		// 创建进程退出等待通道
		done := make(chan struct{})
		go func() {
			if err := cmd.Wait(); err != nil {
				if exiterr, ok := err.(*exec.ExitError); ok {
					if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
						log.Infof("swdevice已退出 (退出码: %d)", status.ExitStatus())
					} else {
						log.Warnf("swdevice已退出 (错误: %v)", err)
					}
				} else {
					log.Errorf("等待swdevice退出失败: %v", err)
				}
			} else {
				log.Info("swdevice已正常退出")
			}
			close(done)
		}()

		// 给进程一点时间正常退出
		log.Info("等待swdevice退出...")
		select {
		case <-done:
			log.Info("swdevice已退出")
		case <-time.After(5 * time.Second):
			// 超时后强制终止
			if cmd.Process != nil {
				log.Warn("等待swdevice退出超时，正在强制终止...")
				if err := cmd.Process.Kill(); err != nil {
					log.Errorf("强制终止swdevice失败: %v", err)
				} else {
					log.Info("swdevice已强制终止")
				}
			} else {
				log.Warn("无活动进程可终止")
			}
		}

		s.rwLock.Lock()
		delete(s.sessMap, connId)
		s.rwLock.Unlock()
	}()

	return nil
}

func NewSwDeviceWindowsServiceImpl(clientSvc UsbIpClientCmdService) SwDeviceService {
	return &SwDeviceWindowsServiceImpl{
		sessMap:   make(map[int64]*vo.SwDeviceInfo),
		clientSvc: clientSvc,
	}
}
